package com.xw.Mail.Receiver;

import java.io.IOException;

import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Store;
import javax.mail.event.MessageCountAdapter;
import javax.mail.event.MessageCountEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.xw.Service.MailService;

public class FatchMailThread extends Thread{
	
	private static final Logger logger = LoggerFactory.getLogger(FatchMailThread.class);
	private static final long Delay = 5000;		//定时延迟时间
	//邮件store
	private Store store;
	//缓存操作业务类
	private MailService mailService;
	//是否继续执行
	private boolean loopFlag = true;
	private KeepIdleAliveThread keepAliveThread;
	private String mailBoxName;
	
	public FatchMailThread(Store store, MailService mailService,String mailBoxName) {
		super();
		this.store = store;
		this.mailService = mailService;
		this.mailBoxName = mailBoxName;
		this.setName("FatchMailThread-"+mailBoxName);
	}

	
	public KeepIdleAliveThread getKeepAliveThread() {
		return keepAliveThread;
	}

	public Store getStore() {
		return store;
	}

	public void setStore(Store store) {
		this.store = store;
	}

	public boolean isLoopFlag() {
		return loopFlag;
	}

	public void setLoopFlag(boolean loopFlag) {
		this.loopFlag = loopFlag;
	}

	public String getMailBoxName() {
		return mailBoxName;
	}

	public void setMailBoxName(String mailBoxName) {
		this.mailBoxName = mailBoxName;
	}


	@Override
	public void run() {
		while(true){
			try {
				getMails(store);
			} catch (Exception e) {
				logger.error("收取邮件线程发生异常终止！尝试重启任务...", e);
			}
		}
	}
	
	/**
	 * 描述：获取邮件方法
	 * @author 杨建全
	 * @date 2017年4月19日
	 * @param store
	 * @throws MessagingException
	 * @throws FolderClosedException
	 * @throws InterruptedException
	 * @throws IOException 
	 */
	private void getMails(final Store store) throws MessagingException{
		if (!store.isConnected()) {
			store.connect();
		}
		IMAPFolder folder = (IMAPFolder) store.getFolder("INBOX");// 获取收件箱
		// 加入邮件监听
		folder.addMessageCountListener(new MessageCountAdapter() {
			@Override
			public void messagesAdded(MessageCountEvent e) {
				// 新邮件来了！
				Message[] msgs = e.getMessages();
				logger.info(mailBoxName + "收到 " + msgs.length + "封新邮件！");
				for (int i = 0; i < msgs.length; i++) {
					mailService.offerNewMailQueue(msgs[i]);
				}
			}
		});
		folder.open(Folder.READ_WRITE); // 以读写方式打开
		// 是否支持idle
		//boolean supportsIdle = true;
		boolean supportsIdle = false;
		
		/**
			//保持idle连接的监控线程
			keepAliveThread = new KeepIdleAliveThread(mailBoxName,folder);
			try {
				keepAliveThread.start();
				folder.idle();
			} catch (FolderClosedException e) {
	            logger.error("收件箱已关闭异常！！！: [DISCONNECT] " + mailBoxName, e);
	        } catch (javax.mail.StoreClosedException e) {
	        	logger.error("StoreClosedException: [GLOBAL DISCONNECT] " + mailBoxName, e);
	        } catch (MessagingException mex) {
				logger.error(mailBoxName + "不支持idle,将启用轮询方式获取新邮件！");
				keepAliveThread.setStop(true);
				supportsIdle = false;
			}
		**/
		while(loopFlag){
			try {
				if (supportsIdle) {
					// 支持idle，那么就执行idle
					// logger.info(mailBoxName + "支持idle,开始尝试执行idle等待新邮件...");
					folder.idle();
				} else {
					// 不支持idle，睡眠一段时间再获取
					Thread.sleep(Delay);
					//logger.info("检查邮箱{}邮件...",mailBoxName);
					// 获取当前邮箱邮件数量
					if (!folder.isOpen()) {
						folder.open(Folder.READ_WRITE); // 以读写方式打开
					}
					folder.getMessageCount();
				}
			} catch (Exception e) {
				logger.error(mailBoxName+"收取邮件循环发送异常：", e);
				if (e instanceof FolderClosedException) {
					try {
						logger.info("尝试重新打开{}收件箱...",mailBoxName);
						folder.open(Folder.READ_WRITE); // 以读写方式打开
					} catch (MessagingException mex) {
						logger.error("尝试重新打开{}收件箱异常！！！",mailBoxName);
					}
				}else if(e instanceof InterruptedException){
					logger.error("收到中断异常，准备停止邮件收取任务....",e);
					loopFlag = false;
				}
				//睡眠1秒后再次尝试
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e1) {
					//不管
					logger.error("",e1);
				}
			} 
		}
		
	}
	
	/**
	 * 描述:保持idle连接的线程
	 * @author 杨建全
	 * @date 2017年4月19日 下午3:59:28
	 */
	public class KeepIdleAliveThread extends Thread {
	    private static final long KEEP_ALIVE_FREQ = 1000*60*1L; // 3 minutes
	    private IMAPFolder folder;		//收件箱
	    private String mailBoxName;		//邮箱名
	    
	    private boolean stop = false;

	    public KeepIdleAliveThread(String mailBoxName,IMAPFolder folder) {
	        this.folder = folder;
	        this.setName("KeepIdleAliveThread-"+mailBoxName);
	        this.mailBoxName = mailBoxName;
	    }
	    
		public void setStop(boolean stop) {
			this.stop = stop;
		}
		@Override
	    public void run() {
	        while (!stop) {
	            try {
	                Thread.sleep(KEEP_ALIVE_FREQ);
	                // Perform a NOOP just to keep alive the connection
	                logger.info(mailBoxName+" 发送Noop命令到邮件服务器以保持idle连接~");
	                folder.doCommand(new IMAPFolder.ProtocolCommand() {
	                    public Object doCommand(IMAPProtocol p)throws ProtocolException {
	                        p.simpleCommand("NOOP", null);
	                        return null;
	                    }
	                });
	            } catch (InterruptedException e) {
	                // Ignore, just aborting the thread...
	            	logger.error("收到中断异常，准备停止与邮件服务器的长连接保障线程...",e);
	            	this.stop = true;
	            } catch (MessagingException e) {
	                // Shouldn't really happen...
	                logger.error("邮箱"+mailBoxName+"发送Noop命令发送异常！", e);
	            }
	        }
	    }
	}
}
